package snapex;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;

import io.swagger.annotations.ApiOperation;
import snapex.SwaggerConfiguration.SwaggerEnableCondition;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
@Conditional(SwaggerEnableCondition.class)
public class SwaggerConfiguration {

	@Value("${snapex.security.enabled}")
	boolean isSecurityEnabled;
	
	@Bean
	public Docket createRestApi() {
		
		Docket docket = new Docket(DocumentationType.SWAGGER_2);
		
		docket.apiInfo(apiInfo()).forCodeGeneration(true);
		
		docket.select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();
		
		if(isSecurityEnabled) {
			docket.securitySchemes(securitySchemes()).securityContexts(securityContexts());
		}
		
		return docket;
		
//		return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).forCodeGeneration(true)
//				.select()
//				.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//				.build();				
//				.securitySchemes(securitySchemes())
//				.securityContexts(securityContexts());
	}

	private List<ApiKey> securitySchemes() {
		List<ApiKey> apiKeyList = new ArrayList();
		apiKeyList.add(new ApiKey("AuthorizationBearer", "Authorization", "header"));
		return apiKeyList;
	}
	
	private List<SecurityContext> securityContexts() {
		List<SecurityContext> securityContexts = new ArrayList<>();
		securityContexts.add(
				SecurityContext.builder()
				.securityReferences(defaultAuth())
				.forPaths(PathSelectors.regex("^(?!auth).*$"))
				.build()
		);
		return securityContexts;
	}

	List<SecurityReference> defaultAuth() {
		AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
		AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
		authorizationScopes[0] = authorizationScope;
		List<SecurityReference> securityReferences = new ArrayList<>();
		securityReferences.add(new SecurityReference("AuthorizationBearer", authorizationScopes));
		return securityReferences;
	}

	private ApiInfo apiInfo() {
		return new ApiInfoBuilder().title("Snapex REST APIs").version("0.1").build();
	}

	static class SwaggerEnableCondition extends SpringBootCondition {

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {

			ConditionMessage.Builder message = ConditionMessage.forCondition("snapex.enableSwagger Condition");

			if ("true".equals(context.getEnvironment().getProperty("snapex.enableSwagger"))) {
				return ConditionOutcome.match(message.foundExactly("snapex.enableSwagger"));
			}

			return ConditionOutcome.noMatch(message.didNotFind("snapex.enableSwagger").atAll());
		}
	}
}
